package bma.common.netty.jvm;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.group.ChannelGroup;

import bma.common.langutil.jmshell.JMShellUtil;
import bma.common.langutil.jmshell.Session;
import bma.common.langutil.jmshell.cmdopt.CommandOptionParser;
import bma.common.langutil.jmshell.command.AbstractSimpleCommandProcessor;
import bma.common.langutil.jmshell.common.JMSPager;

public class NettyListCommand extends AbstractSimpleCommandProcessor {

	public static final String DATA_KEY = "@netty_list";

	public static class NettyInfo {
		public String groupName;
		public ChannelGroup group;
	}

	public NettyListCommand() {
		super("list");
	}

	@Override
	public CommandOptionParser createCommandOption(Session session) {
		CommandOptionParser r = new CommandOptionParser();
		r.addIntegerOption('s', "size", "show connection page size");
		r.addIntegerOption('p', "pos",
				"show connection which position, default last position");
		r.addBooleanOption('r', "reset", "clear connection info cache");
		r.addStringOption('f', "filter", "connection ip filter");
		r.addBooleanOption('c', "create", "create connection info");
		return r;
	}

	@Override
	public boolean processCommand(Session s, String cmd,
			CommandOptionParser options) {
		boolean reset = options.getOptionValue("reset", Boolean.FALSE);
		if (reset) {
			resetPager(s);
			return true;
		}

		boolean create = options.getOptionValue("create", Boolean.FALSE);
		if (create) {
			Collection<String> filters = options.getOptionValues("filter",
					String.class);
			createPager(s, filters);
			return true;
		}
		int sz = options.getOptionValue("size", new Integer(-1));
		if (sz > 0) {
			JMSPager pager = JMSPager.getData(s, DATA_KEY, true);
			pager.setSize(sz);
		}
		connectionInfo(s, options);
		return true;
	}

	public void connectionInfo(Session s, CommandOptionParser options) {

		JMSPager pager = JMSPager.getData(s, DATA_KEY, false);
		if (pager == null) {
			createPager(s, null);
			pager = JMSPager.getData(s, DATA_KEY, false);
		}
		int total = pager == null ? 0 : pager.total();

		s.writeln("[connection " + total + "]");
		if (pager != null) {
			int pos = options.getOptionValue("pos", new Integer(-1));
			pager.show(s, pos, -1, new JMSPager.Render<Channel>() {
				@Override
				public void show(Session s, Channel obj, int pos) {
					showConnectionInfo(s, obj);
				}
			}, Channel.class);
		}
		s.writeln("[connection end]");
	}

	protected void showConnectionInfo(Session s, Channel ch) {
		StringBuilder sb = new StringBuilder();
		sb.append(ch.getRemoteAddress().toString()).append(" - ");
		sb.append(ch.isOpen() ? "OPEN" : "CLOSE");
		s.writeln(sb.toString());
	}

	protected void createPager(Session s, Collection<String> filters) {

		ChannelGroup g = null;
		NettyInfo info = JMShellUtil.getData(s, DATA_KEY, NettyInfo.class,
				false);
		if (info != null) {
			g = info.group;
		}
		if (g == null) {
			s.writeln("ERROR: use 'bind' to bind a channelGroup");
			return;
		}

		Iterator<Channel> cit = g.iterator();
		List<Channel> clist = new ArrayList<Channel>();
		while (cit.hasNext()) {
			clist.add(cit.next());
		}
		Iterator<Channel> it = clist.iterator();
		if (filters != null && filters.size() > 0) {
			while (it.hasNext()) {
				String ip = it.next().getRemoteAddress().toString();
				boolean fmatch = false;
				for (String fi : filters) {
					if (ip.indexOf(fi) != -1) {
						fmatch = true;
						break;
					}
				}
				if (!fmatch) {
					it.remove();
				}
			}
		}

		JMSPager pg = JMSPager.getData(s, DATA_KEY, true);
		pg.init(clist);

		s.writeln("connection info created, use 'list' to view");
	}

	public static void resetPager(Session s) {
		JMSPager pg = JMSPager.getData(s, DATA_KEY, false);
		if (pg != null) {
			pg.reset();
		}
		s.writeln("threadpool info reset");
	}

}